home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / smail-3.1.28 / src / notify.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-20  |  27.7 KB  |  992 lines

  1. /* @(#)src/notify.c    1.14 9/20/92 12:55:00 */
  2.  
  3. /*
  4.  *    Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
  5.  *    Copyright (C) 1992  Ronald S. Karr
  6.  * 
  7.  * See the file COPYING, distributed with smail, for restriction
  8.  * and warranty information.
  9.  */
  10.  
  11. /*
  12.  * notify.c:
  13.  *    keep track of errors and handle notification of the appropriate
  14.  *    users for errors.
  15.  *
  16.  *    external functions: defer_delivery, fail_delivery, succeed_delivery,
  17.  *                error_delivery, process_msg_log, notify
  18.  */
  19. #include <stdio.h>
  20. #include <ctype.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <pwd.h>
  24. #include <signal.h>
  25. #include <time.h>
  26. #include "defs.h"
  27. #include "smail.h"
  28. #include "dys.h"
  29. #include "addr.h"
  30. #include "hash.h"
  31. #include "main.h"
  32. #include "log.h"
  33. #include "direct.h"
  34. #include "route.h"
  35. #include "transport.h"
  36. #include "child.h"
  37. #include "exitcodes.h"
  38. #ifndef DEPEND
  39. # include "extern.h"
  40. # include "debug.h"
  41. #endif
  42.  
  43. /* exported variables */
  44. int send_to_postmaster;            /* set TRUE to mail to postmaster */
  45. int return_to_sender;            /* set TRUE to mail log to sender */
  46.  
  47. /* functions local to this file */
  48. static char *decode_x_line();
  49. static void put_defer_error();
  50. static void classify_addr();
  51. static void notify_new_message();
  52. static struct addr *remove_addr();
  53. static void write_notify_header();
  54.  
  55. /* variables local to this file */
  56. static char *log_banner = "\
  57. |------------------------- Message log follows: -------------------------|\n";
  58. static char *addr_error_banner = "\
  59. |------------------------- Failed addresses follow: ---------------------|\n";
  60. static char *text_banner = "\
  61. |------------------------- Message text follows: ------------------------|\n";
  62.  
  63.  
  64. /*
  65.  * fail_delivery - log that delivery to the set of addresses failed
  66.  */
  67. void
  68. fail_delivery(addr)
  69.     struct addr *addr;            /* list of failed addrs */
  70. {
  71.     register struct addr *cur;
  72.  
  73.     if (addr && exitvalue == EX_OK) {
  74.     exitvalue = EX_UNAVAILABLE;
  75.     }
  76.  
  77.     for (cur = addr; cur; cur = cur->succ) {
  78.     write_log(LOG_SYS,
  79.           "%s ... failed: (ERR_%03ld) %s",
  80.           cur->in_addr,
  81.           cur->error->info & ERR_MASK,
  82.           cur->error->message);
  83.     /* X entries in msg log will be picked up by queue run scans */
  84.     if (cur->parent) {
  85.         write_log(LOG_MLOG,
  86.               "Xfail: <%s> parent: <%s> reason: (ERR_%03ld) %s",
  87.               cur->in_addr,
  88.               cur->parent->in_addr,
  89.               cur->error->info & ERR_MASK,
  90.               cur->error->message);
  91.     } else {
  92.         write_log(LOG_MLOG,
  93.               "Xfail: <%s> reason: (ERR_%03ld) %s",
  94.               cur->in_addr,
  95.               cur->error->info & ERR_MASK,
  96.               cur->error->message);
  97.     }
  98.     }
  99. }
  100.  
  101. /*
  102.  * defer_delivery - log that delivery to the set of addresses is deferred
  103.  *
  104.  * don't write an error message, if it would be a repeat of the most
  105.  * recent deferal message written to the message log file for the
  106.  * address.
  107.  */
  108. void
  109. defer_delivery(addr, defer_errors)
  110.     struct addr *addr;            /* list of succeeded addrs */
  111.     struct defer_addr *defer_errors;    /* previous deferals */
  112. {
  113.     struct addr *cur;
  114.     struct defer_addr *link;
  115.  
  116.     if (addr && exitvalue == EX_OK) {
  117.     exitvalue = EX_TEMPFAIL;
  118.     }
  119.  
  120.     for (cur = addr; cur; cur = cur->succ) {
  121.  
  122.     /* if the deferral's only cause is retry interval, don't log it */
  123.     if (cur->error->info & ERR_DONTLOG) {
  124. #ifndef NODEBUG
  125.         /* but, if debugging, generate a message for human reader */
  126.         if (debug && errfile && debug > 1) {
  127.         fprintf(errfile,
  128.             "%s ... deferred: (ERR_DONTLOG|ERR_%03ld) %s\n",
  129.             cur->in_addr,
  130.             cur->error->info & ERR_MASK,
  131.             cur->error->message);
  132.         }
  133. #endif    /* ! NODEBUG */
  134.         continue;
  135.     }
  136.  
  137.     /* avoid redundant messages */
  138.     for (link = defer_errors; link; link = link->succ) {
  139.         if (EQ(link->address, cur->in_addr) ||
  140.         (link->parent == NULL && cur->parent == NULL) ||
  141.         (link->parent != NULL && cur->parent != NULL &&
  142.          EQ(link->parent, cur->parent->in_addr)))
  143.         {
  144.         break;
  145.         }
  146.     }
  147.     if (link) {
  148.         if (link->error == (cur->error->info & ERR_MASK) &&
  149.         EQ(link->message, cur->error->message))
  150.         {
  151.         break;
  152.         }
  153.     }
  154.  
  155.     write_log((cur->error->info & ERR_CONFERR)? (LOG_SYS|LOG_TTY): LOG_SYS,
  156.           "%s ... deferred: (ERR_%03ld) %s",
  157.           cur->in_addr,
  158.           cur->error->info & ERR_MASK,
  159.           cur->error->message);
  160.     if (cur->parent) {
  161.         write_log(LOG_MLOG,
  162.               "Xdefer: <%s> parent: <%s> reason: (ERR_%03ld) %s",
  163.               cur->in_addr,
  164.               cur->parent->in_addr,
  165.               cur->error->info & ERR_MASK,
  166.               cur->error->message);
  167.     } else {
  168.         write_log(LOG_MLOG,
  169.               "Xdefer: <%s> reason: (ERR_%03ld) %s",
  170.               cur->in_addr,
  171.               cur->error->info & ERR_MASK,
  172.               cur->error->message);
  173.     }
  174.     }
  175. }
  176.  
  177. /*
  178.  * succeed_delivery - log that delivery to the set of addresses succeeded
  179.  */
  180. void
  181. succeed_delivery(addr)
  182.     struct addr *addr;            /* list of succeeded addrs */
  183. {
  184.     register struct addr *cur;
  185.     register struct addr *top;
  186.  
  187.     for (cur = addr; cur; cur = cur->succ) {
  188.     /* find the top parent to log the original in_addr */
  189.     for (top = cur; top->parent; top = top->parent);
  190.  
  191.     if (dont_deliver) {
  192.         write_log(LOG_SYS, "don't deliver %s, debugging",
  193.               top->in_addr);
  194.     } else {
  195.         if (cur->next_host) {
  196.         write_log(LOG_SYS, "delivered%s%s%s%s%s%s%s%s%s%s",
  197.               "\n|\t      via: ", cur->next_host,
  198.               "\n|\t       to: ", cur->next_addr,
  199.               "\n|\t  orig-to: ", top->in_addr,
  200.               "\n|\t   router: ", cur->router->name,
  201.               "\n|\ttransport: ", cur->transport->name);
  202.         } else {
  203.         write_log(LOG_SYS, "delivered%s%s%s%s%s%s%s%s",
  204.               "\n|\t       to: ", cur->next_addr,
  205.               "\n|\t  orig-to: ", top->in_addr,
  206.               "\n|\t director: ", cur->director->name,
  207.               "\n|\ttransport: ", cur->transport->name);
  208.         }
  209.     }
  210.     /* X entries will be picked up by queue run scans */
  211.     if (cur->parent) {
  212.         write_log(LOG_MLOG, "Xsucceed: <%s> parent: <%s>",
  213.               cur->in_addr, cur->parent->in_addr);
  214.     } else {
  215.         write_log(LOG_MLOG, "Xsucceed: <%s>", cur->in_addr);
  216.     }
  217.     }
  218. }
  219.  
  220. /*
  221.  * error_delivery - log that an error was sent for this list of addrs
  222.  *
  223.  * detect mail sent to owners and log the original address.
  224.  */
  225. void
  226. error_delivery(addr)
  227.     struct addr *addr;            /* list of error addrs */
  228. {
  229.     register struct addr *cur;
  230.  
  231.     for (cur = addr; cur; cur = cur->succ) {
  232.     register struct addr *log_addr;
  233.     if (cur->true_addr) {
  234.         log_addr = cur->true_addr;
  235.         write_log(LOG_SYS, "%s ... error sent to %s",
  236.               log_addr->in_addr, cur->in_addr);
  237.     } else {
  238.         if (cur->error->info & ERR_NSENDER) {
  239.         write_log(LOG_SYS, "%s ... error returned to %s",
  240.               cur->in_addr, sender);
  241.         }
  242.         if (cur->error->info & ERR_NPOSTMAST) {
  243.         write_log(LOG_SYS, "%s ... error sent to postmaster",
  244.               cur->in_addr);
  245.         }
  246.     }
  247.     /* X entries will be picked up by queue run scans */
  248.     if (cur->parent) {
  249.         write_log(LOG_MLOG, "Xsent_error: <%s> parent: <%s>",
  250.               cur->in_addr, cur->parent->in_addr);
  251.     } else {
  252.         write_log(LOG_MLOG, "Xsent_error: <%s>", cur->in_addr);
  253.     }
  254.     }
  255. }
  256.  
  257.  
  258. /*
  259.  * process_msg_log - process X lines in the per-message log
  260.  *
  261.  * Lines beginning with X in the per-message log contain information on what
  262.  * mail processing was completed in a previous run on the input spool file.
  263.  * This function takes, as input, the set of addresses which were produced
  264.  * by resolve_addr_list() for delivery and returns a list which does not
  265.  * contain addresses which have already been delivered.
  266.  *
  267.  * It also returns a pointer to information which should be passed to the
  268.  * notify() routine after all the transports have been called.
  269.  */
  270. struct addr *
  271. process_msg_log(in, sent_errors, defer_errors)
  272.     struct addr *in;            /* input resolved addresses */
  273.     struct identify_addr **sent_errors;    /* return errors that have been sent */
  274.     struct defer_addr **defer_errors;    /* last defer message for addrs */
  275. {
  276.     register struct addr *ret;        /* addr list to return */
  277.     char *s;                /* line of text from scan_msg_log() */
  278.     char *m;                /* defer message */
  279.  
  280.     ret = in;
  281.  
  282.     /* scan through all of the lines marked X in the message log file */
  283.     for (s = scan_msg_log(TRUE); s; s = scan_msg_log(FALSE)) {
  284.     char *address;            /* the address to remove */
  285.     char *parent;            /* parent of address to remove */
  286.  
  287.     if (strncmp(s, "Xfail:", sizeof("Xfail:") - 1) == 0) {
  288.         /* get the failed address and the parent address */
  289.         (void) decode_x_line(s + sizeof("Xfail:") - 1 , &address, &parent);
  290.  
  291.         /* remove any occurance from the input list */
  292.         if (address) {
  293.         ret = remove_addr(ret, address, parent);
  294.         }
  295.     } else if (strncmp(s, "Xsucceed:", sizeof("Xsucceed:") - 1) == 0) {
  296.         /* get the delivered address and the parent address */
  297.         (void) decode_x_line(s + sizeof("Xsucceed:") - 1,
  298.                 &address, &parent);
  299.  
  300.         /* remove any occurance from the input list */
  301.         if (address) {
  302.         ret = remove_addr(ret, address, parent);
  303.         }
  304.     } else if (strncmp(s, "Xdefer:", sizeof("Xdefer:") - 1) == 0) {
  305.         /* grab the message and error number of the defered address */
  306.         m = decode_x_line(s + sizeof("Xdefer:") - 1, &address, &parent);
  307.  
  308.         /* put defer message into output defer_error list */
  309.         if (m) {
  310.         put_defer_error(defer_errors, m, address, parent);
  311.         }
  312.     } else if (strncmp(s, "Xsent_error:", sizeof("Xsent_error:")-1) == 0) {
  313.         register struct identify_addr *new_sent;
  314.  
  315.         /* get the sent error address and the parent address */
  316.         (void) decode_x_line(s + sizeof("Xsent_error:") - 1,
  317.                  &address, &parent);
  318.  
  319.         if (address == NULL) {
  320.         continue;
  321.         }
  322.         /* give this address to notify */
  323.         new_sent = (struct identify_addr *)xmalloc(sizeof(*new_sent));
  324.         new_sent->address = COPY_STRING(address);
  325.         if (parent) {
  326.         new_sent->parent = COPY_STRING(parent);
  327.         } else {
  328.         new_sent->parent = NULL;
  329.         }
  330.         new_sent->succ = *sent_errors;
  331.         *sent_errors = new_sent;
  332.     }
  333.     }
  334.  
  335.     return ret;
  336. }
  337.  
  338. /*
  339.  * decode_x_line - decode an X-line from the per-message log file
  340.  *
  341.  * The input should be of the form:
  342.  *
  343.  *    <address> parent: <parent_address> garbage...
  344.  * or    <address> garbage...
  345.  *
  346.  * this routine returns the address and the parent_address.  It also
  347.  * returns a pointer to the garbage.
  348.  */
  349. static char *
  350. decode_x_line(line, address, parent)
  351.     char *line;                /* input line */
  352.     char **address;            /* return address here */
  353.     char **parent;            /* return parent address here */
  354. {
  355.     int level;                /* count < and > nesting */
  356.     register char *p = line;        /* point to parts of the line */
  357.  
  358.     /* skip initial white-space */
  359.     while (isspace(*p)) p++;
  360.  
  361.     /* ignore anything not of the proper form */
  362.     if (*p != '<') {
  363.     *address = NULL;
  364.     return NULL;
  365.     }
  366.     p++;                /* skip the initial < */
  367.  
  368.     /*
  369.      * extract the address as the text up until before the balancing
  370.      * > character, in <address>.
  371.      */
  372.     *address = p;            /* mark this spot as the address */
  373.     level = 1;                /* start at nesting level 1 */
  374.     if (*p == '<') {
  375.     level++;
  376.     }
  377.     while (level > 0) {
  378.     p = address_token(p);
  379.     if (p == NULL) {
  380.         *address = NULL;        /* bad input form */
  381.         return NULL;
  382.     }
  383.     if (*p == '<') {
  384.         level++;
  385.     } else if (*p == '>') {
  386.         --level;
  387.     }
  388.     }
  389.     *p++ = '\0';            /* the last > is the end of address */
  390.  
  391.     /* scan for a possible parent address */
  392.     while (isspace(*p)) p++;        /* skip up until parent: */
  393.  
  394.     /* is there a parent address? */
  395.     if (strncmp(p, "parent:", sizeof("parent:") - 1) != 0) {
  396.     /* no */
  397.     *parent = NULL;
  398.     return p;
  399.     }
  400.     p += sizeof("parent:") - 1;
  401.  
  402.     /* skip initial white-space before actual parent address */
  403.     while (isspace(*p)) p++;
  404.  
  405.     /* ignore anything not of the proper form */
  406.     if (*p != '<') {
  407.     *parent = NULL;
  408.     return NULL;
  409.     }
  410.     p++;                /* skip the initial < */
  411.  
  412.     /*
  413.      * extract the parent as the text up until before the balancing
  414.      * > character, in <parent_addres>
  415.      */
  416.     *parent = p;
  417.     level = 1;
  418.     if (*p == '<') {
  419.     level++;
  420.     }
  421.     while (level > 0){
  422.     p = address_token(p);
  423.     if (p == NULL) {
  424.         *address = NULL;
  425.         return;
  426.     }
  427.     if (*p == '<') {
  428.         level++;
  429.     } else if (*p == '>') {
  430.         --level;
  431.     }
  432.     }
  433.     *p++ = '\0';
  434.  
  435.     while (isspace(*p)) p++;
  436.  
  437.     return p;
  438. }
  439.  
  440. /*
  441.  * put_defer_error - put a deferal message for an address in a list
  442.  *
  443.  * remove previous entries for this address from the list.
  444.  */
  445. static void
  446. put_defer_error(list, message, address, parent)
  447.     struct defer_addr **list;
  448.     char *message;
  449.     char *address;
  450.     char *parent;
  451. {
  452.     int error;
  453.     static char reason_pfx[] = "reason: (ERR_";
  454.     char *p;
  455.     struct defer_addr *link, *next_link, *new_list;
  456.  
  457.     if (strncmp(message, reason_pfx, sizeof(reason_pfx) - 1) != 0) {
  458.     /* doesn't match the correct format */
  459.     return;
  460.     }
  461.     message += sizeof(reason_pfx) - 1;
  462.     p = message;
  463.     while (isdigit(*message)) message++;
  464.     if (*message != ')') {
  465.     /* doesn't match the correct format */
  466.     return;
  467.     }
  468.     *message = 0;
  469.     error = atoi(p);
  470.     *message++ = ')';
  471.     while (isspace(*message)) message++;
  472.  
  473.     new_list = (struct defer_addr *)xmalloc(sizeof(*new_list));
  474.     new_list->succ = NULL;
  475.     new_list->error = error;
  476.     new_list->message = COPY_STRING(message);
  477.     new_list->address = COPY_STRING(address);
  478.     new_list->parent = parent? COPY_STRING(parent): NULL;
  479.  
  480.     for (link = *list; link; link = next_link) {
  481.     next_link = link->succ;
  482.     if (EQ(link->address, address) ||
  483.         (link->parent == NULL && parent == NULL) ||
  484.         (link->parent != NULL && parent != NULL &&
  485.          EQ(link->parent, parent)))
  486.     {
  487.         continue;
  488.     }
  489.     link->succ = new_list;
  490.     new_list = link;
  491.     }
  492.     *list = new_list;
  493. }
  494.  
  495.  
  496. /*
  497.  * notify - notify all users who are to receive a note about errors
  498.  *
  499.  * also, note any configuration errors and set call_defer_message
  500.  * if any are found.  If any addrs exist in the defer list, set
  501.  * some_deferred_addrs to prevent main from calling unlink_spool().
  502.  */
  503. void
  504. notify(defer, fail, sent_errors)
  505.     struct addr *defer;            /* list of deferred addresses */
  506.     struct addr *fail;            /* list of failed addresses */
  507.     struct identify_addr *sent_errors;    /* addrs already handled */
  508. {
  509.     register struct addr *cur;        /* current addr being processed */
  510.     struct addr *next;            /* next addr to process */
  511.     struct addr *to_owner = NULL;    /* addrs to send to addr owners */
  512.     struct addr *verify = NULL;        /* list of owner addrs to verify */
  513.     struct addr *to_other = NULL;    /* to sender and/or postmaster */
  514.     static char *mailargs[] = {
  515.     NULL,
  516. #ifdef GLOTZNET
  517.     "-G", NULL,
  518. #endif /* GLOTZNET */
  519.     "-bS",
  520.     NULL,
  521.     };
  522.     FILE *f;                /* stdin to child process */
  523.     int pid;                /* child process id */
  524.     char *cc1;                /* Cc: address */
  525.     char *cc2;                /* another Cc: address */
  526.  
  527.     DEBUG(DBG_NOTIFY_HI, "notify called\n");
  528.  
  529.     /* set the exec name to the smail binary */
  530.     mailargs[0] = smail;
  531. #ifdef GLOTZNET
  532.     mailargs[2] = glotzhost;
  533. #endif /* GLOTZNET */
  534.  
  535.     /* remove any address which have already been taken care of */
  536.     while (sent_errors) {
  537.     defer = remove_addr(defer, sent_errors->address, sent_errors->parent);
  538.     fail = remove_addr(fail, sent_errors->address, sent_errors->parent);
  539.     sent_errors = sent_errors->succ;
  540.     }
  541.  
  542.     /*
  543.      * for deferred addresses, don't return anything, though note config
  544.      * errors and defer the message if any were found.
  545.      */
  546.     for (cur = defer; cur; cur = next) {
  547.     next = cur->succ;
  548.  
  549.     some_deferred_addrs = TRUE;    /* main should not call unlink_spool */
  550.     if (cur->error->info & ERR_CONFERR) {
  551.         call_defer_message = TRUE;    /* config error, defer whole message */
  552.     }
  553.     }
  554.  
  555.     /*
  556.      * for failed addresses put them in two lists, one list going to
  557.      * the sender or the postmaster, the other list going to addr owners.
  558.      */
  559.     for (cur = fail; cur; cur = next) {
  560.     next = cur->succ;
  561.  
  562.     classify_addr(cur, &to_other, &verify);
  563.     }
  564.  
  565.     /* verify all owners.  If some don't verify, retry classify_addr() */
  566.     while (verify) {
  567.     struct addr *new_list = NULL;    /* unverified addrs */
  568.  
  569.     /*
  570.      * treat defer and fail lists as identical, since we cannot
  571.      * reasonably handle defer addresses here.
  572.      */
  573.     verify_addr_list(verify, &to_owner, &new_list, &new_list);
  574.  
  575.     /* take any new addrs and send through classify_addr */
  576.     verify = NULL;
  577.     for (cur = new_list; cur; cur = next) {
  578.         next = cur->succ;
  579.         classify_addr(cur, &to_other, &verify);
  580.     }
  581.     }
  582.  
  583.     /* sort the list of verified addresses */
  584.     if (to_owner) {
  585.     to_owner = addr_sort(to_owner, OFFSET(addr, in_addr));
  586.     }
  587.  
  588.     if (return_to_sender) {
  589.     /*
  590.      * if return_to_sender is on but the error_processing flag
  591.      * doesn't call for a return message, then turn the flag off.
  592.      */
  593.     if (error_processing != MAIL_BACK && error_processing != WRITE_BACK) {
  594.         return_to_sender = FALSE;
  595.     }
  596.     /* turn it off, as well, for low priority messages */
  597.     if (islower(msg_grade) && msg_grade >= 'n') {
  598.         return_to_sender = FALSE;
  599.     }
  600.     }
  601.  
  602.     /*
  603.      * lastly, if the sender was given as the special string <> or <+>,
  604.      * then an error message failed.  Rather than risk an infinite
  605.      * loop here, defer the message rather than delivering a recursive
  606.      * error message.
  607.      *
  608.      * error message loops can still exist if SMTP is not used or if
  609.      * an intermediate site does not correctly handle the special
  610.      * sender string <>.
  611.      */
  612.     if (error_sender) {
  613.     if (return_to_sender || send_to_postmaster || to_owner) {
  614.         call_defer_message = TRUE;
  615.         return;
  616.     }
  617.     }
  618.  
  619.     /* if nobody needs to be notified, then nothing needs to be done */
  620.     if (! return_to_sender &&
  621.     ! send_to_postmaster &&
  622.     to_owner == NULL)
  623.     {
  624.     return;
  625.     }
  626.  
  627.     /*
  628.      * open a channel to a new smail process, operating in bsmtp mode,
  629.      * and send it messages for all of the recipients.
  630.      */
  631.     pid = open_child(mailargs, (char **)NULL, &f, (FILE **)NULL, -1,
  632.              CHILD_MINENV|CHILD_RETRY, prog_euid, prog_egid);
  633.     if (pid < 0) {
  634.     DEBUG(DBG_NOTIFY_LO, "notify: open_child failed, cannot notify\n");
  635.     /* if we can't notify, let humans interfere later */
  636.     call_defer_message = TRUE;
  637.     return;
  638.     }
  639.  
  640.     /* start up the session */
  641.     (void) fprintf(f, "HELO %s\n", primary_name);
  642.  
  643.     /*
  644.      * if any owners are to receive a message, then send to each
  645.      * owner in turn
  646.      */
  647.     cur = to_owner;
  648.     while (cur) {
  649.     char *last_owner;
  650.  
  651.     /* initiate a new message */
  652.     cc1 = cc2 = NULL;
  653.     if (send_to_postmaster)
  654.         cc1 = "postmaster";
  655.     if (return_to_sender)
  656.         cc2 = sender;
  657.     notify_new_message(f, cur->in_addr, cc1, cc2,
  658.                "sending to address owner");
  659.     send_log(f, FALSE, log_banner);    /* don't include X lines from log */
  660.     (void) fputs(addr_error_banner, f);
  661.     /* write out all of the address errors */
  662.     do {
  663.         if (cur->true_addr->error) {
  664.         (void) fprintf(f, " %s ... failed: %s\n",
  665.                    cur->true_addr->in_addr,
  666.                    cur->true_addr->error->message);
  667.         }
  668.         last_owner = cur->in_addr;
  669.         cur = cur->succ;
  670.     } while (cur && EQIC(last_owner, cur->in_addr));
  671.     (void) fputs(text_banner, f);
  672.     write_notify_header(f);
  673.     putc('\n', f);
  674.     write_body(f, (long)PUT_DOTS);
  675.     (void) fputs(".\n", f);        /* finish the message */
  676.     }
  677.  
  678.     /* if the postmaster is to receive mail, then send it to him (her?) */
  679.     if (send_to_postmaster) {
  680.     int wrote_addr_error_banner = FALSE; /* only write banner once */
  681.  
  682.     cc1 = cc2 = NULL;
  683.     if (return_to_sender)
  684.         cc2 = sender;
  685.     notify_new_message(f, "postmaster", cc1, cc2,
  686.                "sending to postmaster");
  687.     send_log(f, TRUE, log_banner);    /* include X lines from log */
  688.     /* write messages in to_other destined to the postmaster */
  689.     for (cur = to_other; cur; cur = cur->succ) {
  690.         if (cur->error->info & ERR_NPOSTMAST) {
  691.         if (!wrote_addr_error_banner) {
  692.             (void) fputs(addr_error_banner, f);
  693.             wrote_addr_error_banner = TRUE;
  694.         }
  695.         (void) fprintf(f, " %s ... %s\n",
  696.                    cur->in_addr, cur->error->message);
  697.         }
  698.     }
  699.     (void) fputs(text_banner, f);
  700.     write_notify_header(f);
  701.     putc('\n', f);
  702.     write_body(f, (long)PUT_DOTS);
  703.     (void) fputs(".\n", f);        /* finish the message */
  704.     }
  705.  
  706.     /* if the sender is to receive mail, arrange for that */
  707.     if (return_to_sender) {
  708.     int wrote_addr_error_banner = FALSE; /* only write banner once */
  709.  
  710.     cc1 = cc2 = NULL;
  711.     if (send_to_postmaster)
  712.         cc1 = "postmaster";
  713.     notify_new_message(f, sender, cc1, cc2, "returning to sender");
  714.     send_log(f, FALSE, log_banner);    /* don't include X lines from log */
  715.     /* write messages in to_other destined to the sender */
  716.     for (cur = to_other; cur; cur = cur->succ) {
  717.         if (cur->error->info & ERR_NSENDER) {
  718.         if (!wrote_addr_error_banner) {
  719.             (void) fputs(addr_error_banner, f);
  720.             wrote_addr_error_banner = TRUE;
  721.         }
  722.         (void) fprintf(f, " %s ... %s\n",
  723.                    cur->in_addr, cur->error->message);
  724.         }
  725.     }
  726.     (void) fputs(text_banner, f);
  727.  
  728.     /*
  729.      * a message grade between a and z causes body not to be returned.
  730.      * This is handy when notification of errors is desired, but
  731.      * when the overhead of sending the entire message back is not
  732.      * necessary.
  733.      */
  734.     write_notify_header(f);
  735.     putc('\n', f);
  736.     if (islower(msg_grade)) {
  737.         fputs("[low-priority message, body not included]\n", f);
  738.     } else {
  739.         write_body(f, (long)PUT_DOTS);
  740.     }
  741.     (void) fputs(".\n", f);        /* finish the message */
  742.     }
  743.  
  744.     (void) fputs("QUIT\n", f);
  745.  
  746.     (void) close_child(f, (FILE *)NULL, pid);
  747.  
  748.     /* note the addresses for which error messages have been sent */
  749.     error_delivery(to_owner);
  750.     error_delivery(to_other);
  751. }
  752.  
  753.  
  754. /*
  755.  * classify_addr - determine who is to be sent an error message
  756.  *
  757.  * If postmaster or the sender is to receive an error, link into the
  758.  * to_other list, setting send_to_postmaster and/or return_to_sender
  759.  * appropriately.  If a config error is found, set call_defer_message.
  760.  *
  761.  * If we need to send to an owner, determine if an owner string is
  762.  * defined and link an addr structure for that owner into the to_owner
  763.  * list.
  764.  */
  765. static void
  766. classify_addr(addr, to_other, to_owner)
  767.     register struct addr *addr;        /* input address */
  768.     struct addr **to_other;        /* list to sender or postmaster */
  769.     struct addr **to_owner;        /* list to address owner */
  770. {
  771.     int link_to_other = FALSE;        /* TRUE to link into to_other list */
  772.  
  773.     if (error_copy_postmaster)
  774.     addr->error->info |= ERR_NPOSTMAST;
  775.  
  776.     if (addr->error->info & (ERR_NSENDER|ERR_NPOSTMAST)) {
  777.     /* send to either the sender or the postmaster */
  778.     link_to_other = TRUE;
  779.  
  780.     /* note which one */
  781.     if (addr->error->info & ERR_NSENDER) {
  782.         return_to_sender = TRUE;
  783.     }
  784.     if (addr->error->info & ERR_NPOSTMAST) {
  785.         send_to_postmaster = TRUE;
  786.     }
  787.     }
  788.  
  789.     if (addr->error->info & (ERR_NSOWNER|ERR_NPOWNER)) {
  790.     /* send to an address owner, if one is defined and expandable */
  791.     register char *s = NULL;    /* expanded owner string */
  792.     register struct addr *cur;    /* addr for scanning parents */
  793.     char *work_addr;        /* output from preparse_address() */
  794.  
  795.     /*
  796.      * find the closest parent associated with a director that
  797.      * defines an owner string.
  798.      */
  799.     for (cur = addr; cur; cur = cur->parent) {
  800.         char *error;        /* temp for storing parse error */
  801.  
  802.         /*
  803.          * must have a reasonable, expandable owner address
  804.          */
  805.         if (cur->director &&
  806.         cur->director->owner &&
  807.         (s = expand_string(cur->director->owner,
  808.                    (struct addr *)NULL,
  809.                    cur->home,
  810.                    cur->remainder)) &&
  811.         (work_addr = preparse_address(s, &error)))
  812.         {
  813.         break;
  814.         }
  815.     }
  816.     if (cur) {
  817.         /* owner found for the address, build entry in to_owner list */
  818.         struct addr *new = alloc_addr();
  819.  
  820.         new->succ = *to_owner;        /* link */
  821.         *to_owner = new;
  822.         new->in_addr = COPY_STRING(s);    /* copy owner address */
  823.         /*
  824.          * if this addr has already been seen by classify_addr() use
  825.          * the true_addr assigned previously, otherwise this is the
  826.          * first time through, so assign the original addr
  827.          */
  828.         if (addr->true_addr) {
  829.         new->true_addr = addr->true_addr;
  830.         } else {
  831.         new->true_addr = addr;        /* keep track of true addr */
  832.         }
  833.         new->work_addr = work_addr;        /* use the preparsed address */
  834.         /* disable use of smartuser driver */
  835.         new->flags = ADDR_SMARTUSER;
  836.         /*
  837.          * if verify_addr_list() fails to verify this list look higher
  838.          * up for a parent that has an associated owner.
  839.          */
  840.         new->parent = cur->parent;
  841.     } else {
  842.         /* no owner for the address, send to sender and/or postmaster */
  843.         if (addr->true_addr) {
  844.         int perhaps_link = FALSE; /* true to see link, if not linked */
  845.         struct error *true_error = addr->true_addr->error;
  846.  
  847.         if ((addr->error->info & ERR_NSOWNER) ||
  848.             (addr->error->info & ERR_NPOWNER))
  849.         {
  850.             perhaps_link = TRUE;
  851.         }
  852.  
  853.         /* only link if this has not been linked to to_other before */
  854.         if (perhaps_link) {
  855.             if (! (true_error->info & (ERR_NSENDER|ERR_NPOSTMAST)) ) {
  856.             /* link the true address, not this address */
  857.             addr = addr->true_addr;
  858.             link_to_other = TRUE;
  859.             }
  860.         }
  861.         } else {
  862.         link_to_other = TRUE;
  863.         }
  864.         if (addr->error->info & ERR_NSOWNER) {
  865.         addr->error->info |= ERR_NSENDER;
  866.         return_to_sender = TRUE;
  867.         }
  868.         if (addr->error->info & ERR_NPOWNER) {
  869.         addr->error->info |= ERR_NPOSTMAST;
  870.         send_to_postmaster = TRUE;
  871.         }
  872.     }
  873.     }
  874.  
  875.     /* if link_to_other was set anywhere above, link into to_other list */
  876.     if (link_to_other) {
  877.     addr->succ = *to_other;
  878.     *to_other = addr;
  879.     }
  880. }
  881.  
  882. static void
  883. notify_new_message(f, to, cc1, cc2, subject_to)
  884.     FILE *f;
  885.     char *to;                /* recipient */
  886.     char *cc1, *cc2;            /* show carbon copy addresses */
  887.     char *subject_to;            /* message for inclusion in subject */
  888. {
  889.     /*
  890.      * initiate a new message
  891.      * NOTE:  <+> is a smail-internal address form that causes the
  892.      * sender to be considered local, while the SMTP <> address is
  893.      * considered remote.  This is actually important.
  894.      */
  895.     (void) fprintf(f, "MAIL FROM:<+>\n");
  896.  
  897.     /* state the recipient */
  898.     (void) fprintf(f, "RCPT TO:<%s>\n", to);
  899.  
  900.     /* start the message text, with the complete header */
  901.     (void) fprintf(f, "DATA\nFrom: <MAILER-DAEMON@%s>\n", visible_name);
  902.     if (to[0] == '@') {
  903.     /* watch out for route-addrs */
  904.     (void) fprintf(f, "To: <%s>\n", to);
  905.     } else {
  906.     (void) fprintf(f, "To: %s\n", to);
  907.     }
  908.     if (cc1 == NULL && cc2) {
  909.     cc1 = cc2;
  910.     cc2 = NULL;
  911.     }
  912.     if (cc1) {
  913.     if (cc1[0] == '@')
  914.         fprintf(f, "Cc: <%s>", cc1);
  915.     else
  916.         fprintf(f, "Cc: %s", cc1);
  917.     if (cc2) {
  918.         if (cc2[0] == '@')
  919.         fprintf(f, ", <%s>", cc2);
  920.         else
  921.         fprintf(f, ", %s", cc2);
  922.     }
  923.     putc('\n', f);
  924.     }
  925.     (void) fprintf(f, "Subject: mail failed, %s\nReference: <%s@%s>\n\n",
  926.            subject_to, message_id, primary_name);
  927. }
  928.  
  929. /*
  930.  * remove_addr - remove any matched addresses from an input list
  931.  *
  932.  * given an address string and (perhaps) a parent address string and
  933.  * an input address list, remove any occurance of an address in the
  934.  * input list whose in_addr matches the specified address string and
  935.  * whose parent in_addr string matches the specified parent string.
  936.  * If parent is NULL then there must not be a parent address, otherwise
  937.  * there must be a matching parent address.
  938.  */
  939. static struct addr *
  940. remove_addr(in, address, parent)
  941.     struct addr *in;            /* input addr list */
  942.     char *address;            /* address to match against */
  943.     char *parent;            /* parent of address to match */
  944. {
  945.     register struct addr *cur;        /* current address to process */
  946.     struct addr *next;            /* next address to process */
  947.     struct addr *out = NULL;        /* output address list */
  948.  
  949.     for (cur = in; cur; cur = next) {
  950.     next = cur->succ;
  951.  
  952.     if (EQ(cur->in_addr, address)) {
  953.         /* the address does matches */
  954.         if (parent) {
  955.         /* a matching parent is required for a match */
  956.         if (cur->parent && EQ(parent, cur->parent->in_addr)) {
  957.             /* match, don't put it on the output queue */
  958.             DEBUG1(DBG_NOTIFY_LO, "%s ... already delivered\n",
  959.                cur->in_addr);
  960.             continue;
  961.         }
  962.         } else if (cur->parent == NULL) {
  963.         /* match, don't put it on the output queue */
  964.         DEBUG1(DBG_NOTIFY_LO, "%s ... already delivered\n",
  965.                cur->in_addr);
  966.         continue;
  967.         }
  968.     }
  969.  
  970.     /* no match, put the address on the output queue */
  971.     cur->succ = out;
  972.     out = cur;
  973.     }
  974.  
  975.     return out;                /* return the new list */
  976. }
  977.  
  978. static void
  979. write_notify_header(f)
  980.     FILE *f;
  981. {
  982.     struct transport tport;
  983.     struct addr addr;
  984.  
  985.     bzero(&tport, sizeof(tport));
  986.     bzero(&addr, sizeof(addr));
  987.     addr.transport = &tport;
  988.     tport.name = "error";
  989.     tport.flags = PUT_RECEIVED | LOCAL_XFORM;
  990.     write_header(f, &addr);
  991. }
  992.